#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

#include <SDL2/SDL.h>

#include "font_cache.h"

TextSurfaceListEntry *TextSurfaceListGetEntryByKey(TextSurfaceList *list, uint64_t key)
{
    if (!list)
        return NULL;

    TextSurfaceListEntry *entry = list->head;

    while (entry)
    {
        if (entry->key == key)
            return entry;
        entry = entry->next;
    }

    return NULL;
}

TextSurfaceListEntry *TextSurfaceListGetEntryByNumber(TextSurfaceList *list, int n)
{
    if (!list)
        return NULL;

    TextSurfaceListEntry *entry = list->head;

    while (n > 0 && entry)
    {
        n--;
        entry = entry->next;
    }

    if (n != 0)
        return NULL;

    return entry;
}

TextSurfaceListEntry *TextSurfaceListCreatEntry(uint64_t key, SDL_Surface *surface)
{
    if (!surface)
        return NULL;

    TextSurfaceListEntry *entry = malloc(sizeof(TextSurfaceListEntry));
    if (!entry)
        return NULL;

    entry->next = NULL;
    entry->previous = NULL;
    entry->key = key;
    entry->surface = surface;

    return entry;
}

int TextSurfaceListRemoveEntry(TextSurfaceList *list, TextSurfaceListEntry *entry)
{
    if (!list || !entry)
        return 0;

    if (entry->previous)
        entry->previous->next = entry->next;
    else
        list->head = entry->next;

    if (entry->next)
        entry->next->previous = entry->previous;
    else
        list->tail = entry->previous;

    list->length--;

    if (entry->surface)
    {
        if (entry->surface->userdata)
            free(entry->surface->userdata);
        entry->surface->userdata = NULL;
        SDL_FreeSurface(entry->surface);
    }
    free(entry);

    if (list->length == 0)
    {
        list->head = NULL;
        list->tail = NULL;
    }

    return 1;
}

void TextSurfaceListAddEntryToFirst(TextSurfaceList *list, TextSurfaceListEntry *entry)
{
    if (!list || !entry)
        return;

    if (list->length >= list->max_length)
        TextSurfaceListRemoveEntry(list, list->tail);

    entry->next = NULL;
    entry->previous = NULL;

    if (list->head == NULL)
    {
        list->head = entry;
        list->tail = entry;
    }
    else
    {
        TextSurfaceListEntry *head = list->head;
        head->previous = entry;
        entry->next = head;
        list->head = entry;
    }

    list->length++;
}

void TextSurfaceListAddEntryToLast(TextSurfaceList *list, TextSurfaceListEntry *entry)
{
    if (!list || !entry)
        return;

    if (list->length >= list->max_length)
        TextSurfaceListRemoveEntry(list, list->head);

    entry->next = NULL;
    entry->previous = NULL;

    if (list->head == NULL)
    {
        list->head = entry;
        list->tail = entry;
    }
    else
    {
        TextSurfaceListEntry *tail = list->tail;
        tail->next = entry;
        entry->previous = tail;
        list->tail = entry;
    }

    list->length++;
}

void TextSurfaceListMoveEntryToFirst(TextSurfaceList *list, TextSurfaceListEntry *entry)
{
    if (!list)
        return;

    if (entry->previous)
        entry->previous->next = entry->next;
    else
        list->head = entry->next;

    if (entry->next)
        entry->next->previous = entry->previous;
    else
        list->tail = entry->previous;

    entry->next = NULL;
    entry->previous = NULL;

    if (list->head == NULL)
    {
        list->head = entry;
        list->tail = entry;
    }
    else
    {
        TextSurfaceListEntry *head = list->head;
        head->previous = entry;
        entry->next = head;
        list->head = entry;
    }
}

void TextSurfaceListMoveEntryToLast(TextSurfaceList *list, TextSurfaceListEntry *entry)
{
    if (!list)
        return;

    if (entry->previous)
        entry->previous->next = entry->next;
    else
        list->head = entry->next;

    if (entry->next)
        entry->next->previous = entry->previous;
    else
        list->tail = entry->previous;

    entry->next = NULL;
    entry->previous = NULL;

    if (list->head == NULL)
    {
        list->head = entry;
        list->tail = entry;
    }
    else
    {
        TextSurfaceListEntry *tail = list->tail;
        tail->next = entry;
        entry->previous = tail;
        list->tail = entry;
    }
}

void TextSurfaceListEmpty(TextSurfaceList *list)
{
    if (!list)
        return;

    TextSurfaceListEntry *entry = list->head;

    while (entry)
    {
        TextSurfaceListEntry *next = entry->next;
        if (entry->surface)
        {
            if (entry->surface->userdata)
                free(entry->surface->userdata);
            entry->surface->userdata = NULL;
            SDL_FreeSurface(entry->surface);
        }
        free(entry);
        entry = next;
    }

    list->head = NULL;
    list->tail = NULL;
    list->length = 0;
}
